package coupon

import (
	"context"
	"strconv"
	"strings"

	"mall/common/globalkey"
	"mall/common/jwt"
	"mall/common/resultx"
	"mall/common/utils/pointy"
	"mall/service/forum/api/internal/logic/promotion/util"
	"mall/service/forum/api/internal/svc"
	"mall/service/forum/api/internal/types"
	"mall/service/forum/api/internal/utils/parse"
	"mall/service/promotion/rpc/promotionclient"

	"github.com/zeromicro/go-zero/core/logx"
)

type GetUserCouponListLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewGetUserCouponListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetUserCouponListLogic {
	return &GetUserCouponListLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *GetUserCouponListLogic) GetUserCouponList(
	req *types.GetUserCouponListReq,
	headers *[]*types.Header,
) (resp *types.CouponListInfo, err error) {
	userId := jwt.GetUserId(l.ctx)
	if userId == 0 {
		return nil, resultx.NewErrCode(resultx.TOKEN_EXPIRE_ERROR)
	}

	page, pageSize := parse.ParsePageInfo(
		req.Current,
		req.PageSize,
		l.svcCtx.Config.Query.DefaultAmount,
		l.svcCtx.Config.Query.MaxAmount,
	)

	// Todo: 删除无用字段
	preload := "coupon:Id,ActivityId,TemplateId,Code,UserId,OrderId,StartedAt,EndedAt,UsedAt,Status"
	preload += ";couponTemplate:Id,Name,Desc,Members,Type,Mutex,Scope,Mode,Threshhold,DiscountMode,DiscountValue"
	preload += ";promotionMeta:mediaUrl"
	preload += ";promotionMedia:Uid,Uri,Url,Thumbnail,Order,altText"
	eagerLoad := "coupon:couponTemplate,promotionMeta,promotionMedia"

	filters := []string{"UserId,equalTo:" + strconv.FormatUint(userId, 10)}
	if req.Type != nil {
		switch *req.Type {
		case 1: // 待使用
			filters = append(filters, "Status,equalTo:"+strconv.FormatInt(int64(globalkey.StatusStarted), 10))
		case 2: // 已使用
			filters = append(filters, "Status,equalTo:"+strconv.FormatInt(int64(globalkey.StatusUsed), 10))
		case 3: // 优惠券已过期或优惠券对应的活动已下架
			filters = append(filters, "Status,in:"+strconv.FormatInt(int64(globalkey.StatusFinished), 10)+","+strconv.FormatInt(int64(globalkey.StatusInvalid), 10))
		}
	}

	res, err := l.svcCtx.PromotionRpc.GetUserCouponList(l.ctx, &promotionclient.BaseListReq{
		Offset:     uint32((page - 1) * pageSize),
		Limit:      uint32(pageSize),
		Preload:    pointy.GetPointer(preload),
		EagerLoad:  pointy.GetPointer(eagerLoad),
		Filter:     pointy.GetPointer(strings.Join(filters, ";")),
		Sorter:     req.Sorter,
		VisitorId:  pointy.GetPointer(userId),
		PlatformId: pointy.GetPointer(globalkey.ThirdPartyPlatformWechatMini),
	})
	if err != nil {
		logx.Errorw("GetUserCouponList err", logx.Field("detail", err.Error()))
		return nil, err
	}

	var hasNextPage bool
	var hasPreviousPage bool
	if res.HasNextPage != nil && *res.HasNextPage > 0 {
		hasNextPage = true
	}
	if res.HasPreviousPage != nil && *res.HasPreviousPage > 0 {
		hasPreviousPage = true
	}

	resp = &types.CouponListInfo{
		BaseListInfo: types.BaseListInfo{
			Current:         page,
			PageSize:        pageSize,
			HasNextPage:     hasNextPage,
			HasPreviousPage: hasPreviousPage,
		},
	}

	for _, v := range res.List {
		var rule *promotionclient.CouponTemlateInfo
		if v.Rule != nil {
			var timeRange []string
			if v.StartedAt != nil && v.EndedAt != nil {
				timeRange = []string{*v.StartedAt, *v.EndedAt}
			}

			rule = v.Rule
			couponTypeText := util.GetCouponTypeText(rule.CouponType)
			mutexTypeText := util.GetMutexTypeText(rule.MutexType)
			scopeTypeText := util.GetScopeTypeText(rule.ScopeType)
			modeText := util.GetCouponModeText(rule.Condition)
			var threshold *string
			if rule.ConditionValue != nil {
				if tips := strings.Split(modeText, ","); len(tips) > 0 && len(tips[0]) > 0 {
					threshold = pointy.GetPointer(strings.Replace(tips[0], "N", *rule.ConditionValue, 1))
				}
			}

			var discount *string
			if rule.DiscountMode != nil && rule.DiscountValue != nil {
				discount = pointy.GetPointer(util.GetDiscountValue(rule.DiscountMode, rule.DiscountValue))
			}
			statusText := util.GetCouponStatusText(v.Status)

			var mediaUrl *string
			if len(rule.Meta) > 0 {
				for _, m := range rule.Meta {
					if m.Key == nil || m.Value == nil {
						continue
					}

					switch *m.Key {
					case "mediaUrl":
						mediaUrl = m.Value
					}
				}
			}

			var media []*types.TmpMediaInfo
			if len(rule.Media) > 0 {
				for _, m := range rule.Media {
					var url string
					if m.Url != nil && len(*m.Url) > 0 {
						url = *m.Url
					}
					if len(url) == 0 && m.Uri != nil && len(*m.Uri) > 0 {
						url = *m.Uri
					}

					media = append(media, &types.TmpMediaInfo{
						Uid:       m.Uid,
						Thumbnail: m.Thumbnail,
						Order:     m.Order,
						Url:       pointy.GetPointer(url),
						AltText:   m.AltText,
					})
				}
			} else if mediaUrl != nil {
				media = append(media, &types.TmpMediaInfo{
					Thumbnail: pointy.GetPointer(uint32(1)),
					Order:     pointy.GetPointer(uint32(0)),
					Url:       mediaUrl,
				})
			}

			resp.List = append(resp.List, &types.CouponInfo{
				CouponTemplateInfo: types.CouponTemplateInfo{
					Id:                rule.Id,
					Name:              rule.Name,
					Description:       rule.Desc,
					MemberRestriction: rule.MemberRestriction,
					CouponType:        rule.CouponType,
					CouponTypeText:    pointy.GetPointer(couponTypeText),
					MutexType:         rule.MutexType,
					MutexTypeText:     pointy.GetPointer(mutexTypeText),
					ScopeType:         rule.ScopeType,
					ScopeTypeText:     pointy.GetPointer(scopeTypeText),
					Mode:              rule.Condition,
					ModeText:          pointy.GetPointer(modeText),
					Threshold:         threshold,
					DiscountMode:      rule.DiscountMode,
					Discount:          discount,
					Media:             media,
				},
				CouponId:   v.Id,
				ActivityId: v.ActivityId,
				TemplateId: v.TemplateId,
				Code:       v.Code,
				UserId:     v.UserId,
				OrderId:    v.OrderId,
				TimeRange:  timeRange,
				UsedAt:     v.UsedAt,
				Status:     v.Status,
				StatusText: pointy.GetPointer(statusText),
				Threshold:  threshold,
			})
		}
	}

	resp.Total = res.Total

	return resp, nil
}
